package com.ph.shopping.facade.member.service.dbservice.facade.impl;

import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ph.shopping.common.core.customenum.MemberEnum;
import com.ph.shopping.common.core.customenum.ResultEnum;
import com.ph.shopping.common.core.exception.BizException;
import com.ph.shopping.common.core.other.bankcard.BankCardCheckService;
import com.ph.shopping.common.util.container.ClassOperateUtil;
import com.ph.shopping.common.util.container.ContainerUtil;
import com.ph.shopping.common.util.container.ParamVerifyUtil;
import com.ph.shopping.common.util.result.Result;
import com.ph.shopping.facade.customfactory.CustomBeanImpl;
import com.ph.shopping.facade.customfactory.CustomBeanRule;
import com.ph.shopping.facade.customfactory.facade.ICustomBeanFactory;
import com.ph.shopping.facade.duboresult.DubboResult;
import com.ph.shopping.facade.mapper.BankCardMapper;
import com.ph.shopping.facade.mapper.MemberMapper;
import com.ph.shopping.facade.member.dto.BankBindInfoDto;
import com.ph.shopping.facade.member.dto.BankCardBindInfoDto;
import com.ph.shopping.facade.member.dto.BankCardInfoPageDto;
import com.ph.shopping.facade.member.entity.BankBindCardLog;
import com.ph.shopping.facade.member.entity.BankCardBind;
import com.ph.shopping.facade.member.entity.BankCardInfo;
import com.ph.shopping.facade.member.entity.BankCodeAndName;
import com.ph.shopping.facade.member.entity.Member;
import com.ph.shopping.facade.member.service.dbservice.facade.IBankCardDbService;
import com.ph.shopping.facade.member.vo.UnbundBankCardInfoVo;
/**
 * 
* @ClassName: BankCardServiceImpl  
* @Description: 银行卡绑定服务类  
* @author tony  
* @date 2017年3月15日  
*
 */
@Service
public class BankCardDbService implements IBankCardDbService{

	private static final Logger log = LoggerFactory.getLogger(BankCardDbService.class);
	
	@Autowired
	private ICustomBeanFactory<CustomBeanRule> customBeanFactory;
	
	@Autowired
	private BankCardMapper bankCardMapper;
	
	@Autowired
	private BankCardCheckService backCardCheckService;
	
	@Autowired
	private MemberMapper memeberMapper;

	@Override
	@Transactional
	public Result bindBankCardInfo(BankBindInfoDto dto) {
		Result result = DubboResult.getResultByEnum(ResultEnum.MEMBER_FAILURE);
		final Long accountId = dto.getAccountId();
		final String cardNum = dto.getCardNum();
		final Byte userType = dto.getUserType();
		// 判断用户是否已绑定该银行卡
		if (isUserBindBankCard(accountId, cardNum, userType)) {
			result = DubboResult.getResultByEnum(ResultEnum.MEMBER_DATA_EXISTS);
		} else {
			BankCardInfo bankCardInfo = new BankCardInfo();
			BeanUtils.copyProperties(dto, bankCardInfo);
			// 如果是会员则判断是否已实名认证
			if (MemberEnum.MEMEBR_BANK.getCode().equals(userType)) {
				if (!checkIdCardAuth(dto.getAccountId())) {
					result.setCode(ResultEnum.ID_NOT_CERTIFIED.getCode());
					result.setMessage(ResultEnum.ID_NOT_CERTIFIED.getMsg());
					return result;
				}
			}
			// 验证银行卡
			boolean flag = backCardCheckService.bankCardAuth(dto.getIdCard(), dto.getCardNum(), dto.getOwnName());
			if (!flag) {
				result.setCode(ResultEnum.BANK_CHECK_FAIL.getCode());
				result.setMessage(ResultEnum.BANK_CHECK_FAIL.getMsg());
				return result;
			}
			BankCardInfo existsBankInfo = getExistsBankInfo(accountId, cardNum, userType);
			if (existsBankInfo == null || StringUtils.isBlank(existsBankInfo.getCardNum())) {
				bankCardInfo.setIsDelete(MemberEnum.CARD_NORMAL.getCode());
				bankCardInfo.setCreateTime(new Date());
				bankCardInfo.setBankName(replaceCardName(bankCardInfo.getBankName()));
				bankCardMapper.insertUseGeneratedKeys(bankCardInfo);
			} else {
				bankCardInfo = existsBankInfo;// 此处用于跟新信息
			}

			BankCardBind banCardBindInfo = backBankCardBindInfo(bankCardInfo);
			if (banCardBindInfo == null || banCardBindInfo.getBankCardInfoId() == null) {
				log.warn("银行卡信息ID 为空不能执行绑定操做");
				throw new BizException("银行卡信息ID 为空不能执行绑定操做");
			}
			// 判断用户是否已绑定了银行卡，绑定了则解绑 再绑定新卡（备注：目前只能绑定一张银行卡）
			unbundBankByOther(accountId, userType);
			BankCardBindInfoDto bankBindInfo = getBankCardBindInfoDto(accountId, cardNum, userType);
			if (bankBindInfo != null && bankBindInfo.getBindId() != null) {
				// 存在绑定关系数据时 则修改数据
				BankCardBind bankCard = new BankCardBind();
				bankCard.setBindStatus(MemberEnum.CARD_BOUND.getCode());
				bankCard.setUpdateTime(new Date());
				bankCard.setId(bankBindInfo.getBindId());
				bankCardMapper.updateBankCardBind(bankCard);
			} else {
				// 新增绑定关系
				bankCardMapper.insertBankCardBind(banCardBindInfo);
			}
			// 插入绑定数据历史
			BankBindCardLog bankBindCardLog = backBankBindCardLog(bankCardInfo);
			bankCardMapper.insertBankBindCardLog(bankBindCardLog);
			result = DubboResult.getResultBySuccess(result);
		}
		return result;
	}
	/**
	 * 
	 * @Title: replaceCardNum   
	 * @Description: 解决银行卡名称转义字符   
	 * @param: @param cardNum
	 * @param: @return      
	 * @return: String      
	 * @throws
	 */
	private String replaceCardName(String cardName) {
		if (StringUtils.isNotBlank(cardName)) {
			cardName = cardName.replaceAll("& #40;", "\\(").replaceAll("& #41;", "\\)");
		}
		return cardName;
	}
	/**
	 * 
	 * @Title: unbundBankByOther   
	 * @Description: 解绑最新绑定的银行卡  
	 * @param: @param userId
	 * @param: @param userType
	 * @param: @return      
	 * @return: boolean      
	 * @throws
	 */
	private boolean unbundBankByOther(Long userId, Byte userType) {
		BankCardBindInfoDto bindBankInfo = getUserBindBankInfoByUid(userId, userType);
		if (bindBankInfo != null) {
			BankCardBind bankCard = new BankCardBind();
			bankCard.setBindStatus(MemberEnum.CARD_UNBOUND.getCode());
			bankCard.setUpdateTime(new Date());
			bankCard.setId(bindBankInfo.getBindId());
			bankCardMapper.updateBankCardBind(bankCard);
			return true;
		}
		return false;
	}
	/**
	 * 
	 * @Title: checkIdCardAuth   
	 * @Description: 如果是会员则判断是否已实名认证
	 * @param: @param userId
	 * @param: @return      
	 * @return: boolean      
	 * @throws
	 */
	private boolean checkIdCardAuth(Long userId) {
		boolean flag = false;
		if (userId != null) {
			Member member = memeberMapper.selectMemberInfoById(userId);
			flag = (member != null && MemberEnum.CERTIFICATION.getCode().equals(member.getCertification()));
		}
		return flag;
	}
	/**
	 * 
	* @Title: getExistsBankInfo  
	* @Description: 查询用户是否已添加了银行卡
	* @param @param userId
	* @param @param cardNum
	* @param @return    参数  
	* @return BankCardInfo    返回类型  
	* @throws
	 */
	private BankCardInfo getExistsBankInfo(Long userId,String cardNum,Byte userType){
		BankCardInfo existsBankInfo = null;
		if(userId != null && StringUtils.isNotBlank(cardNum)){
			Map<String, Object> map = ContainerUtil.map();
			map.put("accountId", userId);
			map.put("cardNum", cardNum);
			map.put("userType", userType);
			existsBankInfo = bankCardMapper.selectBankCardInfoByCardNum(map);
		}
		return existsBankInfo;
	}
	/**
	 * 
	* @Title: isUserBindBankCard  
	* @Description: 判断用户是否已绑定了银行卡  
	* @param @param userId
	* @param @param cardId
	* @param @return    参数  
	* @return boolean    返回类型  
	* @throws
	 */
	private boolean isUserBindBankCard(Long userId, String cardNum,Byte userType) {
		Map<String, Object> map = ContainerUtil.map();
		map.put("userId", userId);
		map.put("cardNum", cardNum);
		map.put("bindStatus", MemberEnum.CARD_BOUND.getCode());
		map.put("userType", userType);
		BankCardBindInfoDto info = bankCardMapper.selectUserBindBankCardByUid(map);
		return info != null && StringUtils.isNotBlank(info.getCardNum());
	}
	/**
	 * 
	 * @Title: getBankCardBindInfoDto   
	 * @Description: 查询银行卡是否在绑定关系表里存在   
	 * @param: @param userId
	 * @param: @param cardNum
	 * @param: @param userType
	 * @param: @return      
	 * @return: BankCardBindInfoDto      
	 * @throws
	 */
	private BankCardBindInfoDto getBankCardBindInfoDto(Long userId, String cardNum,Byte userType){
		Map<String, Object> map = ContainerUtil.map();
		map.put("userId", userId);
		map.put("cardNum", cardNum);
		map.put("userType", userType);
		return bankCardMapper.selectUserBindBankCardByUid(map);
	}
	/**
	 * 
	* @Title: backBankCardBindInfo  
	* @Description: 封装绑定关系数据  
	* @param @param bankCardInfo
	* @param @return    参数  
	* @return BankCardBind    返回类型  
	* @throws
	 */
	private BankCardBind backBankCardBindInfo(BankCardInfo bankCardInfo) {
		BankCardBind cardBind = null;
		if (bankCardInfo != null) {
			cardBind = new BankCardBind();
			cardBind.setBankCardInfoId(bankCardInfo.getId());
			cardBind.setUserId(bankCardInfo.getAccountId());
			cardBind.setCreateTime(new Date());
			cardBind.setBindStatus(MemberEnum.CARD_BOUND.getCode());
		}
		return cardBind;
	}
	/**
	 * 
	* @Title: backBankBindCardLog  
	* @Description: 封装卡片操作历史数据  
	* @param @param bankCardInfo
	* @param @return    参数  
	* @return BankBindCardLog    返回类型  
	* @throws
	 */
	private BankBindCardLog backBankBindCardLog(BankCardInfo bankCardInfo) {
		BankBindCardLog bankBindCardLog = null;
		if (bankCardInfo != null) {
			try {
				String[] logFields = ClassOperateUtil.getFiledStrByClassBySuper(BankBindCardLog.class);
				Map<String, String> map = CustomBeanImpl.getKeyValues(logFields);
				String[] noAssignmentFields = { "id" };
				CustomBeanRule customBean = new CustomBeanRule(map, bankCardInfo, noAssignmentFields);
				bankBindCardLog = customBeanFactory.generateAppointBean(customBean, BankBindCardLog.class);
			} catch (Exception e) {
				log.error("back BankBindCardLog data error ", e);
			}
		}
		return bankBindCardLog;
	}

	@Override
	@Transactional
	public Result UnbundBankCardInfo(UnbundBankCardInfoVo unbundBankCardInfo) {
		Result result = DubboResult.getResultBySuccess();
		Map<String, Object> map = ContainerUtil.map();
		map.put("userId", unbundBankCardInfo.getUserId());
		map.put("cardNum", unbundBankCardInfo.getCardNum());
		map.put("bindStatus", MemberEnum.CARD_BOUND.getCode());
		map.put("userType", unbundBankCardInfo.getUserType());
		BankCardBindInfoDto info = bankCardMapper.selectUserBindBankCardByUid(map);
		if (info != null && info.getBindId() != null) {
			BankCardBind bankCard = new BankCardBind();
			bankCard.setBindStatus(MemberEnum.CARD_UNBOUND.getCode());
			bankCard.setUpdateTime(new Date());
			bankCard.setId(info.getBindId());
			bankCardMapper.updateBankCardBind(bankCard);
		}else{
			result.setCode(ResultEnum.MEMBER_NO_DATA.getCode());
			result.setMessage("未查询到该用户绑定的银行卡信息");
		}
		return result;
	}

	@Override
	public Result queryBankCardInfoList(BankCardInfo bankCard) {
		Result result = DubboResult.getDefResultByImpl();
		List<BankCardInfo> list = bankCardMapper.selectBankCardInfoList(bankCard);
		if (ParamVerifyUtil.objIsNotNull(list)) {
			result.setData(list);
			result = DubboResult.getResultBySuccess(result);
		}
		return result;
	}

	@Override
	public Result queryBankCardInfoByPage(BankCardInfoPageDto dto) {
		Result result = DubboResult.getDefResultByImpl();
		Map<String, Object> map = null;
		try {
			map = customBeanFactory.beanToMap(dto);
		} catch (Exception e) {
			log.error("BankCardInfoPageDto to map error", e);
		}
		if (map != null) {
			PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
			List<BankCardInfo> list = bankCardMapper.selectBankCardInfoByPage(map);
			PageInfo<BankCardInfo> page = new PageInfo<BankCardInfo>(list);
			result.setCount(page.getTotal());
			result.setData(page.getList());
			result = DubboResult.getResultBySuccess(result);
		}
		return result;
	}
	
	@Override
	public Result queryBankCardInfoById(Long id) {
		Result result = DubboResult.getDefResultByImpl();
		BankCardInfo bankCardInfo = bankCardMapper.selectByPrimaryKey(id);
		if (bankCardInfo != null) {
			result.setData(bankCardInfo);
			result = DubboResult.getResultBySuccess(result);
		}
		return result;
	}

	@Override
	public Result queryUserBindBankCardListByUserId(Long userId,Byte userType) {
		Result result = DubboResult.getDefResultByImpl();
		List<BankCardBindInfoDto> list = getUserBindBankInfos(userId, userType);
		if (ParamVerifyUtil.objIsNotNull(list)) {
			result.setData(list);
			result = DubboResult.getResultBySuccess(result);
		}
		return result;
	}
	/**
	 * 
	 * @Title: getUserBindBankInfos   
	 * @Description: 获取用户绑定的银行卡信息   
	 * @param: @param userId
	 * @param: @param userType
	 * @param: @return      
	 * @return: List<BankCardBindInfoDto>      
	 * @throws
	 */
	private List<BankCardBindInfoDto> getUserBindBankInfos(Long userId,Byte userType){
		Map<String, Object> map = ContainerUtil.map();
		map.put("userId", userId);
		map.put("userType", userType);
		map.put("bindStatus", MemberEnum.CARD_BOUND.getCode());
		return bankCardMapper.selectUserBindBankCardList(map);
	}
	@Override
	public Result queryBankCodeAndNameByCode(String bankCode) {
		Result result = DubboResult.getDefResultByImpl();
		String cardbinSix  = bankCode.substring(0,6);//获取6位开头的bin
		BankCodeAndName info = bankCardMapper.selectBankCodeAndNameByCode(cardbinSix);
		if(info == null || StringUtils.isBlank(info.getBankCode())){
			String cardbinEight = bankCode.substring(0,8);//获取8位开头的bin
			info = bankCardMapper.selectBankCodeAndNameByCode(cardbinEight);
		}
		if(info != null){
			result.setData(info);
			result = DubboResult.getResultBySuccess(result);
		}
		return result;
	}
	
	@Override
	public Result queryBankCardInfo(Long userId, Byte userType) {
		Result result = DubboResult.getDefResultByImpl();
		BankCardBindInfoDto bindInfo = getUserBindBankInfoByUid(userId, userType);
		if (bindInfo != null) {
			result.setData(bindInfo);
			result = DubboResult.getResultBySuccess(result);
		}
		return result;
	}
	/**
	 * 
	 * @Title: getUserBindBankInfoByUid   
	 * @Description:获取最新一张绑定的银行卡（备注：目前用户只能绑定一张卡，所以只需要查询一张）   
	 * @param: @param userId
	 * @param: @param userType
	 * @param: @return      
	 * @return: BankCardBindInfoDto      
	 * @throws
	 */
	private BankCardBindInfoDto getUserBindBankInfoByUid(Long userId, Byte userType) {
		Map<String, Object> map = ContainerUtil.map();
		map.put("userId", userId);
		map.put("bindStatus", MemberEnum.CARD_BOUND.getCode());
		map.put("userType", userType);
		List<BankCardBindInfoDto> info = bankCardMapper.selectUserBindBankCard(map);
		if (ParamVerifyUtil.objIsNotNull(info)) {
			return info.get(0);
		}
		return null;
	}
}
